import { BridgeMessage, PendingRequest, MethodHandler, BridgeOptions, EventCallback } from "../types";
import { generateId, validateMessage, Logger, BridgeError } from "../utils";
import { EventBus } from "./EventBus";

export class FastBridge {
  // 存储等待响应的请求
  private pendingRequests: Map<string, PendingRequest> = new Map();

  // 存储注册的方法
  private registeredMethods: Map<string, MethodHandler> = new Map();

  // 事件总线
  private eventBus: EventBus;

  // 日志工具
  private logger: Logger;

  // 命名空间
  private namespace: string;

  // 角色：host 或 client
  private role: "host" | "client";

  // iframe 元素（仅宿主页面有）
  private iframe?: HTMLIFrameElement;

  // 安全配置
  private strictOrigin: boolean;
  private allowedOrigins: Set<string>;
  private debugMode: boolean;

  // 连接状态
  private isConnected: boolean = false;

  // 是否正在连接
  private isConnecting: boolean = false;

  // 连接 Promise
  private connectionPromise: Promise<void> | null = null;

  // 等待发送的消息队列
  private pendingMessages: BridgeMessage[] = [];

  // MessageChannel 端口
  private port: MessagePort | null = null;

  // 消息统计
  private messageStats = {
    sent: 0,
    received: 0,
    errors: 0,
    lastSent: 0,
    lastReceived: 0,
  };

  constructor(options: BridgeOptions) {
    this.namespace = options.namespace || "default";
    this.iframe = options.iframe;
    this.role = this.iframe ? "host" : "client";

    // 安全配置
    this.strictOrigin = options.security?.strictOrigin !== false; // 默认严格
    this.allowedOrigins = new Set(options.security?.allowedOrigins || []);
    this.debugMode = options.debug || false;

    this.logger = new Logger({
      debug: options.debug || false,
      role: this.role.toUpperCase() as "HOST" | "CLIENT",
    });
    this.eventBus = new EventBus();

    // 注册内置方法
    this._registerBuiltinMethods();

    this.logger.log(
      `FastBridge 初始化完成，角色: ${this.role}, 严格源验证: ${this.strictOrigin}, 调试模式: ${this.debugMode}`
    );
  }

  // 初始化方法 - 用户只需要调用这个方法，内部处理所有时序问题
  async init(): Promise<void> {
    // 如果已经连接，直接返回
    if (this.isConnected) {
      this.logger.log("已经连接，跳过连接过程");
      return;
    }

    // 如果正在连接，等待连接完成
    if (this.isConnecting && this.connectionPromise) {
      this.logger.log("正在连接中，等待连接完成");
      return this.connectionPromise;
    }

    // 开始连接
    this.isConnecting = true;
    this.connectionPromise = this._connect();

    try {
      await this.connectionPromise;
    } finally {
      this.isConnecting = false;
    }
  }

  // 实际的连接逻辑 - 内部处理所有时序问题
  private async _connect(): Promise<void> {
    this.logger.log("开始建立连接...");

    if (this.role === "host") {
      // 宿主页面：等待 iframe 准备就绪，然后建立连接
      await this._connectAsHost();
    } else {
      // iframe 页面：等待宿主连接
      await this._connectAsClient();
    }

    this.isConnected = true;
    this.logger.log("连接建立成功");

    // 发送队列中的消息
    this._flushPendingMessages();

    // 触发连接状态变化事件
    this.eventBus.emit("connectionChange", true);
  }

  // 宿主连接逻辑 - 自动处理 iframe 加载和准备就绪
  private async _connectAsHost(): Promise<void> {
    this.logger.log("以宿主身份连接...");
    if (!this.iframe) {
      throw new Error("宿主页面必须提供 iframe 元素");
    }

    // 标准连接模式：等待 iframe 完全准备就绪
    // 1. 等待 iframe 加载完成（优化后更快）
    await this._waitForIframeLoad();

    // 2. 等待 iframe 准备就绪（减少超时时间）
    await this._waitForIframeReady();

    // 3. 创建 MessageChannel 并发送给 iframe
    await this._establishMessageChannel();
  }

  // 等待 iframe 加载完成
  private async _waitForIframeLoad(): Promise<void> {
    if (!this.iframe) {
      throw new Error("宿主页面必须提供 iframe 元素");
    }

    return new Promise((resolve) => {
      // 如果开启调试模式，跳过 contentDocument 检查以避免跨域错误
      if (this.debugMode) {
        this.logger.log("调试模式：跳过 iframe contentDocument 检查");
        // 等待 iframe 加载完成
        this.iframe!.onload = () => {
          this.logger.log("iframe onload 事件触发");
          resolve();
        };

        // 设置超时，避免无限等待
        setTimeout(() => {
          this.logger.warn("iframe 加载超时，尝试继续连接");
          resolve();
        }, 1000);
        return;
      }

      // 检查 iframe 是否已经加载完成
      if (this.iframe!.contentWindow && this.iframe!.contentDocument?.readyState === "complete") {
        // iframe 已经加载完成
        this.logger.log("iframe 已加载完成");
        resolve();
        return;
      }

      // 检查 iframe 是否已经加载到 interactive 状态
      if (this.iframe!.contentDocument?.readyState === "interactive") {
        this.logger.log("iframe 已加载到交互状态");
        resolve();
        return;
      }

      // 等待 iframe 加载完成
      this.iframe!.onload = () => {
        this.logger.log("iframe onload 事件触发");
        resolve();
      };

      // 设置超时，避免无限等待
      setTimeout(() => {
        this.logger.warn("iframe 加载超时，尝试继续连接");
        resolve();
      }, 1000); // 固定 1 秒超时
    });
  }

  // 等待 iframe 准备就绪
  private async _waitForIframeReady(): Promise<void> {
    return new Promise((resolve) => {
      const handleMessage = (event: MessageEvent) => {
        // 验证消息来源
        if (!this._isOriginAllowed(event.origin)) {
          this.logger.warn(`拒绝来自未授权源的消息: ${event.origin}`);
          return;
        }

        if (event.data?.type === "iframe-ready" && event.data?.namespace === this.namespace) {
          window.removeEventListener("message", handleMessage);
          this.logger.log("iframe 已准备就绪");
          resolve();
        }
      };

      window.addEventListener("message", handleMessage);

      // 如果开启调试模式，使用固定超时时间避免跨域错误
      let timeout: number;
      if (this.debugMode) {
        timeout = 2000; // 调试模式使用固定 2 秒超时
      } else {
        // 如果 iframe 已经加载完成，减少等待时间
        timeout = this.iframe?.contentDocument?.readyState === "complete" ? 500 : 2000;
      }

      setTimeout(() => {
        window.removeEventListener("message", handleMessage);
        this.logger.warn(`等待 iframe 准备就绪超时（${timeout}ms），尝试直接连接`);
        resolve();
      }, timeout);
    });
  }

  // 验证源是否被允许
  private _isOriginAllowed(origin: string): boolean {
    // 如果开启调试模式，允许跨源
    if (this.debugMode) {
      this.logger.log(`调试模式：允许跨源请求来自 ${origin}`);
      return true;
    }

    // 如果不严格验证源，检查允许列表
    if (!this.strictOrigin) {
      if (this.allowedOrigins.size === 0) {
        return true; // 允许所有源
      }
      return this.allowedOrigins.has(origin);
    }

    // 严格验证：只允许同源和 iframe 源
    // 如果是同源，允许
    if (origin === window.location.origin) {
      return true;
    }

    // 如果是 iframe 的源，允许
    if (this.iframe && this.iframe.src) {
      try {
        const iframeUrl = new URL(this.iframe.src);
        if (origin === iframeUrl.origin) {
          return true;
        }
      } catch (error) {
        // URL 解析失败，可能是相对路径
        return true; // 相对路径认为是安全的
      }
    }

    // 其他源拒绝
    return false;
  }

  // 建立 MessageChannel 连接
  private async _establishMessageChannel(): Promise<void> {
    if (!this.iframe) {
      throw new Error("宿主页面必须提供 iframe 元素");
    }

    // 创建 MessageChannel
    const channel = new MessageChannel();
    const port1 = channel.port1; // 宿主使用 port1
    const port2 = channel.port2; // 发送给 iframe

    // 设置消息监听
    port1.onmessage = (event) => {
      this._handleMessage(event.data);
    };

    // 发送初始化消息给 iframe，同时传递 port2
    const initMessage = {
      type: "init",
      namespace: this.namespace,
      channelId: generateId(),
      timestamp: Date.now(),
    };

    // 获取 iframe 的 origin
    const targetOrigin = this._getIframeOrigin();

    this.logger.log("发送初始化消息给 iframe");
    this.iframe.contentWindow!.postMessage(initMessage, targetOrigin, [port2]);

    // 保存端口和目标窗口
    this.port = port1;
    // this.targetWindow = this.iframe.contentWindow; // 删除未使用的targetWindow
  }

  // 获取 iframe 的 origin
  private _getIframeOrigin(): string {
    // 如果开启调试模式，使用通配符允许跨域
    if (this.debugMode) {
      this.logger.log("调试模式：使用通配符 origin 允许跨域通信");
      return "*";
    }

    if (!this.iframe || !this.iframe.src) {
      return window.location.origin; // 默认使用当前源
    }

    try {
      const iframeUrl = new URL(this.iframe.src);
      return iframeUrl.origin;
    } catch (error) {
      // URL 解析失败，可能是相对路径，使用当前源
      return window.location.origin;
    }
  }

  // iframe 客户端连接逻辑
  private async _connectAsClient(): Promise<void> {
    this.logger.log("以客户端身份等待连接...");

    // 1. 通知宿主已准备就绪
    this._notifyHostReady();

    // 2. 等待宿主发送 MessageChannel
    await this._waitForHostConnection();
  }

  // 通知宿主已准备就绪
  private _notifyHostReady(): void {
    const readyMessage = {
      type: "iframe-ready",
      namespace: this.namespace,
      timestamp: Date.now(),
    };

    this.logger.log("通知宿主已准备就绪");

    // 如果开启调试模式，使用通配符允许跨域
    const targetOrigin = this.debugMode ? "*" : window.parent.location.origin;
    window.parent.postMessage(readyMessage, targetOrigin);
  }

  // 等待宿主连接
  private async _waitForHostConnection(): Promise<void> {
    return new Promise((resolve) => {
      const handleMessage = (event: MessageEvent) => {
        // 验证消息来源
        if (!this._isOriginAllowed(event.origin)) {
          this.logger.warn(`拒绝来自未授权源的消息: ${event.origin}`);
          return;
        }

        if (event.data?.type === "init" && event.data?.namespace === this.namespace) {
          // 获取传递过来的端口
          const port = event.ports[0];
          if (port) {
            // 设置消息监听
            port.onmessage = (portEvent) => {
              this._handleMessage(portEvent.data);
            };

            // 保存端口和目标窗口
            this.port = port;
            // this.targetWindow = window.parent; // 删除未使用的targetWindow

            this.logger.log("收到宿主的 MessageChannel 连接");
            window.removeEventListener("message", handleMessage);
            resolve();
          }
        }
      };

      window.addEventListener("message", handleMessage);
    });
  }

  // 发送队列中的消息
  private _flushPendingMessages(): void {
    if (this.pendingMessages.length > 0) {
      this.logger.log(`发送队列中的 ${this.pendingMessages.length} 条消息`);
      this.pendingMessages.forEach((message) => {
        this._sendMessage(message);
      });
      this.pendingMessages = [];
    }
  }

  // 发送消息
  private _sendMessage(message: BridgeMessage): void {
    if (!this.port) {
      this.logger.warn("连接未建立，消息已加入队列", message);
      this.pendingMessages.push(message);
      return;
    }

    // 更新发送统计
    this.messageStats.sent++;
    this.messageStats.lastSent = Date.now();

    // 序列化消息以确保可以安全传输
    const serializedMessage = this._serializeMessage(message);

    try {
      this.port.postMessage(serializedMessage);
      this.logger.log("发送消息:", message);
    } catch (error) {
      this.logger.error("发送消息失败:", error);
      this.messageStats.errors++;
    }
  }

  // 序列化消息，处理不可克隆的对象
  private _serializeMessage(message: BridgeMessage): BridgeMessage {
    const serialized = { ...message };

    // 处理请求消息的参数
    if (serialized.type === "request" && serialized.params) {
      serialized.params = this._serializeData(serialized.params);
    }

    // 处理响应消息的结果
    if (serialized.type === "response" && serialized.result) {
      serialized.result = this._serializeData(serialized.result);
    }

    // 处理事件消息的数据
    if (serialized.type === "event" && serialized.data) {
      serialized.data = this._serializeData(serialized.data);
    }

    return serialized;
  }

  // 序列化数据，移除不可克隆的属性
  private _serializeData(data: any): any {
    if (data === null || data === undefined) {
      return data;
    }

    if (typeof data === "string" || typeof data === "number" || typeof data === "boolean") {
      return data;
    }

    if (Array.isArray(data)) {
      return data.map((item) => this._serializeData(item));
    }

    if (typeof data === "object") {
      // 处理Date对象
      if (data instanceof Date) {
        return { __type: "Date", value: data.toISOString() };
      }

      // 处理RegExp对象
      if (data instanceof RegExp) {
        return { __type: "RegExp", source: data.source, flags: data.flags };
      }

      // 处理Error对象
      if (data instanceof Error) {
        return {
          __type: "Error",
          name: data.name,
          message: data.message,
          stack: data.stack,
        };
      }

      // 处理普通对象，移除不可克隆的属性
      const serialized: any = {};
      for (const [key, value] of Object.entries(data)) {
        // 跳过函数、Symbol、DOM节点等不可克隆的属性
        if (
          typeof value === "function" ||
          typeof value === "symbol" ||
          value instanceof Node ||
          value instanceof Window ||
          value instanceof Element
        ) {
          continue;
        }

        try {
          serialized[key] = this._serializeData(value);
        } catch (error) {
          this.logger.warn(`跳过不可序列化的属性: ${key}`, error);
        }
      }
      return serialized;
    }

    return data;
  }

  // 处理接收到的消息
  private _handleMessage(message: any): void {
    // 更新接收统计
    this.messageStats.received++;
    this.messageStats.lastReceived = Date.now();

    // 反序列化消息
    const deserializedMessage = this._deserializeMessage(message);

    // 验证消息格式
    if (!validateMessage(deserializedMessage)) {
      this.logger.warn("收到无效消息格式:", deserializedMessage);
      this.messageStats.errors++;
      return;
    }

    // 验证命名空间
    if (deserializedMessage.namespace !== this.namespace) {
      this.logger.warn("收到不匹配命名空间的消息:", deserializedMessage.namespace);
      this.messageStats.errors++;
      return;
    }

    this.logger.log("收到消息:", deserializedMessage);

    // 根据消息类型处理
    switch (deserializedMessage.type) {
      case "request":
        this._handleRequest(deserializedMessage);
        break;
      case "response":
        this._handleResponse(deserializedMessage);
        break;
      case "event":
        this._handleEvent(deserializedMessage);
        break;
      default:
        this.logger.warn("未知消息类型:", deserializedMessage.type);
        this.messageStats.errors++;
    }
  }

  // 反序列化消息，恢复特殊对象
  private _deserializeMessage(message: any): any {
    const deserialized = { ...message };

    // 处理请求消息的参数
    if (deserialized.type === "request" && deserialized.params) {
      deserialized.params = this._deserializeData(deserialized.params);
    }

    // 处理响应消息的结果
    if (deserialized.type === "response" && deserialized.result) {
      deserialized.result = this._deserializeData(deserialized.result);
    }

    // 处理事件消息的数据
    if (deserialized.type === "event" && deserialized.data) {
      deserialized.data = this._deserializeData(deserialized.data);
    }

    return deserialized;
  }

  // 反序列化数据，恢复特殊对象
  private _deserializeData(data: any): any {
    if (data === null || data === undefined) {
      return data;
    }

    if (typeof data === "string" || typeof data === "number" || typeof data === "boolean") {
      return data;
    }

    if (Array.isArray(data)) {
      return data.map((item) => this._deserializeData(item));
    }

    if (typeof data === "object") {
      // 恢复Date对象
      if (data.__type === "Date") {
        return new Date(data.value);
      }

      // 恢复RegExp对象
      if (data.__type === "RegExp") {
        return new RegExp(data.source, data.flags);
      }

      // 恢复Error对象
      if (data.__type === "Error") {
        const error = new Error(data.message);
        error.name = data.name;
        error.stack = data.stack;
        return error;
      }

      // 处理普通对象
      const deserialized: any = {};
      for (const [key, value] of Object.entries(data)) {
        deserialized[key] = this._deserializeData(value);
      }
      return deserialized;
    }

    return data;
  }

  // 处理请求消息
  private async _handleRequest(message: any): Promise<void> {
    const { id, method, params } = message;

    if (!method) {
      this._sendErrorResponse(id, "方法名是必需的");
      return;
    }

    const handler = this.registeredMethods.get(method);
    if (!handler) {
      this._sendErrorResponse(id, `方法 '${method}' 未找到`);
      return;
    }

    try {
      this.logger.log(`处理请求: ${method}`);
      const result = await handler(params);
      this._sendResponse(id, result);
    } catch (error) {
      this._sendErrorResponse(id, error instanceof Error ? error.message : "未知错误");
    }
  }

  // 处理响应消息
  private _handleResponse(message: any): void {
    const { id, result, error } = message;
    const pendingRequest = this.pendingRequests.get(id);

    if (!pendingRequest) {
      this.logger.warn("未找到ID对应的待处理请求:", id);
      return;
    }

    this.pendingRequests.delete(id);

    if (error) {
      this.logger.log(`请求失败: ${error}`);
      pendingRequest.reject(new BridgeError(error, "REMOTE_ERROR"));
    } else {
      this.logger.log("请求成功");
      pendingRequest.resolve(result);
    }
  }

  // 处理事件消息
  private _handleEvent(message: any): void {
    const { event, data } = message;
    if (event) {
      this.logger.log(`处理事件: ${event}`);
      this.eventBus.emit(event, data);
    }
  }

  // 发送响应
  private _sendResponse(id: string, result: any): void {
    const message = {
      id,
      type: "response" as const,
      namespace: this.namespace,
      result,
      timestamp: Date.now(),
    };
    this._sendMessage(message);
  }

  // 发送错误响应
  private _sendErrorResponse(id: string, error: string): void {
    const message = {
      id,
      type: "response" as const,
      namespace: this.namespace,
      error,
      timestamp: Date.now(),
    };
    this._sendMessage(message);
  }

  // 注册方法供对方调用
  register(methodName: string, handler: MethodHandler): void {
    this.registeredMethods.set(methodName, handler);
    this.logger.log(`方法已注册: ${methodName}`);
  }

  // 调用对方注册的方法
  async call<T>(methodName: string, params?: any): Promise<T> {
    this.logger.log(`调用方法: ${methodName}`);

    const id = generateId();
    const message = {
      id,
      type: "request" as const,
      namespace: this.namespace,
      method: methodName,
      params,
      timestamp: Date.now(),
    };

    return new Promise((resolve, reject) => {
      // 存储待处理请求
      this.pendingRequests.set(id, { resolve, reject });

      // 发送消息
      this._sendMessage(message);
    });
  }

  // 发送事件
  emit(eventName: string, data?: any): void {
    this.logger.log(`发送事件: ${eventName}`);

    const message = {
      id: generateId(),
      type: "event" as const,
      namespace: this.namespace,
      event: eventName,
      data,
      timestamp: Date.now(),
    };

    this._sendMessage(message);
  }

  // 监听事件
  on(eventName: string, callback: EventCallback): void {
    this.eventBus.on(eventName, callback);
    this.logger.log(`事件监听器已添加: ${eventName}`);
  }

  // 监听连接状态变化
  onConnectionChange(callback: (connected: boolean) => void): void {
    this.eventBus.on("connectionChange", callback);
  }

  // 获取事件总线
  getEventBus(): EventBus {
    return this.eventBus;
  }

  // 获取连接状态
  getConnectionStatus(): boolean {
    return this.isConnected;
  }

  // 获取连接信息
  getConnectionInfo(): {
    connected: boolean;
    connecting: boolean;
    role: "host" | "client";
    namespace: string;
    targetOrigin?: string;
  } {
    return {
      connected: this.isConnected,
      connecting: this.isConnecting,
      role: this.role,
      namespace: this.namespace,
      targetOrigin: this.iframe ? this._getIframeOrigin() : undefined,
    };
  }

  // 断开连接
  disconnect(): void {
    this.logger.log("断开连接");

    // 清理连接状态
    this.isConnected = false;
    this.isConnecting = false;
    this.connectionPromise = null;

    // 关闭端口
    if (this.port) {
      this.port.close();
      this.port = null;
    }

    // 清理目标窗口
    // this.targetWindow = null; // 删除未使用的targetWindow

    // 清理待处理请求
    this.pendingRequests.clear();

    // 清理消息队列
    this.pendingMessages.length = 0;

    // 触发连接状态变化事件
    this.eventBus.emit("connectionChange", false);

    this.logger.log("连接已断开");
  }

  // 重连机制
  async reconnect(): Promise<void> {
    this.logger.log("尝试重连...");

    // 先断开当前连接
    this.disconnect();

    // 等待一小段时间
    await new Promise((resolve) => setTimeout(resolve, 100));

    // 重新连接
    await this.init();
  }

  // 检查连接健康状态
  async ping(): Promise<number> {
    if (!this.isConnected) {
      throw new BridgeError("连接未建立", "NOT_CONNECTED");
    }

    const startTime = Date.now();

    try {
      await this.call("__ping__", { timestamp: startTime });
      return Date.now() - startTime;
    } catch (error) {
      throw new BridgeError("连接异常", "CONNECTION_ERROR");
    }
  }

  // 注册内置方法
  private _registerBuiltinMethods(): void {
    // 注册 ping 方法
    this.register("__ping__", async (params) => {
      return { pong: true, timestamp: params.timestamp };
    });
  }

  // 获取消息统计
  getMessageStats(): typeof this.messageStats {
    return { ...this.messageStats };
  }

  // 重置消息统计
  resetMessageStats(): void {
    this.messageStats = {
      sent: 0,
      received: 0,
      errors: 0,
      lastSent: 0,
      lastReceived: 0,
    };
  }
}
